##
## Ldap.py 
##
## Offers ldap functionality for cwsAdmin script.
## (ie create group, create user)
##
## Author: Shannon Eric Peevey <speeves@erikin.com>, 20 September 2004
##

import ldap, re, sys, os, md5, base64
from Report import ReportFunc
from types import *

class LdapFunc:
    """
    LDAP functionality for cwsAdmin.  This class allows
    you to search an ldap server, create groups, add users to
    groups, etc.
    """

    def LdapSearchInterface(self, config, utilityObject, ldapsearch=""):
        """ Searches the ldap server for a user based on 'filter' """

        # connect to the server and bind
        ldapConn = self.Connect(config)

        filter = self.LdapSearchPrompt(ldapsearch)

        ## DEBUGGING
        if config['General']["debugLevel"] == '1':
            print "filter ==", filter
            
        # Check to see if this is a user search, or group object search
        # based on the attribute it is searching.
        if filter == 'q' or filter == 'h':
            filterDict = ''
        elif filter != 'b':
            for attr in config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]['ldapUserAttributes']:
                regexpSplitEquals = re.compile(r'[=]')
                splitAttr = regexpSplitEquals.split(filter)
                ## DEBUGGING
                if config['General']["debugLevel"] == '5':
                    print "config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]['ldapUserAttributes'] == ", config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]['ldapUserAttributes']

                if splitAttr[0] == attr:
                    ## DEBUGGING
                    if config['General']["debugLevel"] == '5':
                        print "splitAttr == ", splitAttr
                        print "splitAttr[0] == ", splitAttr[0]
                        print "attr == ", attr

                    # we check for attributes so that we can choose which LDAP tree to search
                    if attr == 'sn' or attr == 'givenname' or attr == 'uid':
                        searchType = '1'
                        break
                    elif attr == 'cn':
                        regexpFilter = re.compile(r'.*[*].*')
                        cnGroupOrUser = regexpFilter.match(filter)
                        if cnGroupOrUser == None:
                            searchType = '0'
                        else:
                            # splitAttr[0] == euid or uid (for example)
                            searchType = '1'
                        break
                    else:
                        searchType = '1'
                        break
                else:
                    searchType = '0'

            ## DEBUGGING
            if config['General']["debugLevel"] == '5':
                print "searchType (0 = group, 1 = uid) == ", searchType

            # set the 
            # do search
            filterDict = self.LdapSearch(config, filter, searchType)

            ## DEBUGGING
            if config['General']["debugLevel"] == '5':
                print "filterDict == ", filterDict

            filterDict = self.LdapSearchPrint(config, utilityObject, filterDict, filter)
            ## DEBUGGING
            if config['General']["debugLevel"] == '5':
                print "filterDict == ", filterDict
                print "type(filterDict) == ", type(filterDict)
                
        else:
            filterDict = self.NavigateTree(config, '', 1)

        ## DEBUGGING
        if config['General']["debugLevel"] == '5':
            print "filterDict == ", filterDict
            
        # unbind from the server
        self.Disconnect(ldapConn)

        return filterDict


    def GetObjectClassDict(self, config):
        """ get a listing of the ldapschema dir, split the files on the .,
            and return a list of objectClasses """
                           
        # get a listing of the files in 
        objectClassLdifFiles = os.listdir(config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["ldapObjectClassDir"])
        
        # remove .ldif from the file names
        availableObjectClassDict = {}
        for f in objectClassLdifFiles:
            ## DEBUGGING
            if config['General']["debugLevel"] == '5':
                print "f == ", f
                
            if f != "README.txt":
                o, p, e = f.split(".")
                availableObjectClassDict[o] = p

        return availableObjectClassDict


    def PrintObjectClassMenu(self, config, availableObjectClassDict):
        """ print the availableObjectClassDict as a menu """
        # loop until the user inputs a valid entry
        goodChoice = "n"
        while goodChoice == "n":
            # print objectClass choices from availableObjectClassDict[0]
            print "Choose from the following list of objectClasses"
            print

            ## DEBUGGING
            if config['General']["debugLevel"] == '5':
                print "availableObjectClassDict == ", availableObjectClassDict
                
            availableObjectClassList = []
            for i, p in availableObjectClassDict.iteritems():
                availableObjectClassList.append(i)
                
            iterator = 1
            for o in availableObjectClassList:
                print "(" + str(iterator) + ") " + o
                iterator = iterator + 1
            chooseObjectClass = input("objectClass ? ")

            chooseObjectClass = chooseObjectClass - 1
            if chooseObjectClass < 0 or chooseObjectClass > len(availableObjectClassDict):
                continue
            else:
                ## DEBUGGING
                if config['General']["debugLevel"] == '5':
                    print "availableObjectClassList == ", availableObjectClassList
                    print "availableObjectClassDict[availableObjectClassList[chooseObjectClass]] == ", availableObjectClassDict[availableObjectClassList[chooseObjectClass]]
                    print "availableObjectClassList[chooseObjectClass] == ", availableObjectClassList[chooseObjectClass]
                    
                goodChoice = "y"
                objectClass = availableObjectClassList[chooseObjectClass]
                

        return objectClass
        

    def LdapAddObject(self, config, utilityObject):
        """ Add/Remove objects.
            1. GetObjectClassDict(self, config)
             - get a listing of available objectClasses from the ldapschema directory
             - get a list of files from ldapschema files
             - remove .ldif from file name (ie organizationalUnit.ldif becomes organizationalUnit)
            2. PrintMenuFromObjectClassDict(self, objectClassDict)
             - print menu list of objects to add/remove from available objectClasses
             - get needed information to modify object class
              - need to get array of variable names from ldif
               - CheckSkelLines function to do this
               - variables are surrounded with [variableName]
               - prompt with variables names as variable, and as prompt text (ou: [ou] = ou: ? )
             - create attribute array
             - call ldapCreateObject or ldapDeleteObject
        """
        ## DEBUGGING
        if config['General']["debugLevel"] == '5':
            import pdb; pdb.set_trace()

        # get a listing of the ldapschema dir, split the files on the .,
        #    and return a list of objectClasses
        availableObjectClassDict = self.GetObjectClassDict(config)

        # print the menu, and let the user choose the objectClass
        objectClass = self.PrintObjectClassMenu(config, availableObjectClassDict)

        # set the prefix of the new object
        objectClassPrefix = availableObjectClassDict[objectClass]
        
        ##
        print "\nAdd LDAP " + objectClass + "\n"

        print "This tool will help you to Add a(n) " + objectClass + " under "
        print "the correct container. First, we will need to decide where to create "
        print "the " + objectClass + ".  To do this, please browse to the location you would like to "
        print "create the " + objectClass + ": \n"

        # Search or navigate tree to get to group for adding/removing member
        baseDn = self.LdapSearchInterface(config, utilityObject)

        ## DEBUGGING
        if config['General']["debugLevel"] == '5':
            print "baseDn == ", baseDn
            print "len(baseDn) == ", len(baseDn)

        # set the baseDn by the type of object it is
        try:
            if type(baseDn) is StringType:
                pass
            elif type(baseDn) is TupleType:
                baseDn = baseDn[0]
            elif type(baseDn) is ListType:
                baseDn = baseDn[0]
                if type(baseDn) is TupleType:
                    # check to see if baseDn is a list with nested tuple
                    baseDn = baseDn[0]
        except:
            baseDn = ''
            print
            print "No Results were returned.  Please try again."
            print

        # test to see if baseDn is empty (which means the user 'q')
        if baseDn != '':
            # print header for getting the  id
            print "\nNext, we need the name of the " + objectClass + "(s) that we would like "
            print "to add. You can enter as many " + objectClass + "(s) as you would like."
            print ""
            print "Press 'q' to finish adding " + objectClass + "\n"

            # set text for prompt
            objectName = objectClass + " Name? (q => finish) [q] "
            # grab single/multiple groupNames
            objectNameList = utilityObject.GetObjectId(config, objectName)

            # check addRemove to see if we are going to add the object
            ## DEBUGGING
            if config['General']["debugLevel"] == '5':
                print "objectNameList == ", objectNameList
                print "len(objectNameList) == ", len(objectNameList)

            for objectName in objectNameList:
                objectAttributes = self.CreateObjectAttributes(config, utilityObject, objectClass, objectClassPrefix, objectName, baseDn)
                if config['General']["debugLevel"] == '5':
                    print "baseDn == ", baseDn
                    # print "baseDn[0] == ", baseDn[0]
                    # print "baseDn[1] == ", baseDn[1]

                #if not baseDn[0]
                dn = objectAttributes.pop(0)
                if config['General']["debugLevel"] == '5':
                    print "dn == ", dn
                    print "objectAttributes == ", objectAttributes

                # create the object
                self.LdapCreateObject(config, dn, objectAttributes)


    def CreateObjectAttributes(self, config, utilityObject, objectClass, objectClassPrefix, objectName, baseDn):
        """ 1. open the correct ldif
            2. grab the lines in the file
            3. search/replace variables within lines of the file
            3a.create 
            4. pass the attributes to LdapCreateObject
            """
        ldifFile = utilityObject.GrabTextList(config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["ldapObjectClassDir"] + objectClass + "." + objectClassPrefix + ".ldif")

        # create python list from ldif
        objectAttributes = self.SplitLdifIntoPythonAttributesList(config, utilityObject, objectClassPrefix, objectName, baseDn, ldifFile)
        #####DEBUGGING
        if config['General']["debugLevel"] == '5':
            print "objectAttributes == ", objectAttributes

        return objectAttributes

    def ReplaceLdifVariables(self, config, utilityObject, line, baseDn):
        """ Read each line from the LDIF file, and replace the variables
            with the correct information

            1. check each line in ldifContents for a variable in the form:
             - [attribute:single|multi:datatype:default value]
            2. If variable is found, split the variable into a list on ":"
            3. check session variable to see if the attribute is already defined.
            4. if not, check if value is single or multi valued attribute and run the single or multi prompt function (prompt with the attribute name)
            5. once we have chosen single or multi, then we gather user info
               and check it against the datatype for sanitization.
            6. if answer is "", check for variable[3], and if it exists, set
               the default value, if not prompt again...
            """
        # remove the variable symbols
        line = line.replace("[", "")
        line = line.replace("]", "")
        # split line into a two field array on ":"
        splitOnColon = line.split(':', 1)
        # set attributeVariableConfig to splitOnColon[1]
        attributeVariableConfig = splitOnColon[1]
        attributeVariableConfig = attributeVariableConfig.strip()
        # split attributeVariableConfig on ":"
        attributeVariableList = attributeVariableConfig.split(":")
        # get length of attributeVariableList (if length is 3, then there
        # is no default value
        lengthAttributeVariableList = len(attributeVariableList)

        ## DEBUGGING
        if config['General']["debugLevel"] == '5':
            print "line == ", line
            print "splitOnColon == ", splitOnColon
            print "attributeVariableConfig == ", attributeVariableConfig
            print "attributeVariableList == ", attributeVariableList
            print "lengthAttributeVariableList == ", lengthAttributeVariableList
            
        # attribute may only appear once in object
        attributeVariableValue = ""
        while attributeVariableValue == "":
            if attributeVariableList[1] == "single":
                # call utilityObject.GetObjectId() to replace value
                attributeVariableValue = utilityObject.GetObjectId(config,  attributeVariableList[0] + "? (q => finish) [q] ", "", attributeVariableList[2], 1)

                # if the value is boolean, convert it to LDAP acceptable format
                if attributeVariableList[2] == "boolean":
                    if attributeVariableValue == "t":
                        attributeVariableValue = "TRUE"
                    else:
                        attributeVariableValue = "FALSE"
                elif attributeVariableList[2] == "password":
                    #####DEBUGGING
                    if config['General']["debugLevel"] == '5':
                        print "attributeVariableValue  == ", attributeVariableValue
                        import pdb; pdb.set_trace()

                    # we need to test if attributeVariableValue is a listtype
                    if type(attributeVariableValue) is ListType:
                        # attributeVariableValue[0] is empty, then we generate a random password
                        if attributeVariableValue[0] == "":
                            password = utilityObject.GeneratePassword(config)
                            encryptPassword = md5.new(password).digest()
                            attributeVariableValue = '{md5}' + base64.b64encode(encryptPassword)
                        else:
                            attributeVariableValue = '{md5}' + base64.b64encode(attributeVariableValue[0])
                    else:
                        if attributeVariableValue == "":
                            password = utilityObject.GeneratePassword(config)
                            encryptPassword = md5.new(password).digest()
                            attributeVariableValue = '{md5}' + base64.b64encode(encryptPassword)
                        else:
                            attributeVariableValue = '{md5}' + base64.b64encode(attributeVariableValue)

                if type(attributeVariableValue) is ListType:
                    if attributeVariableValue == []:
                        line = str(splitOnColon[0]) + ": "
                    else:
                        line = str(splitOnColon[0]) + ": " + str(attributeVariableValue[0])
                else:
                    if attributeVariableValue == "":
                        line = str(splitOnColon[0]) + ": "
                    else:
                        line = str(splitOnColon[0]) + ": " + str(attributeVariableValue)
            else:
                # attribute may have multiple attributes
                attributeVariableValue = utilityObject.GetObjectId(config,  attributeVariableList[0] + "? (q => finish) [q] ", "", attributeVariableList[2])

                if len(attributeVariableValue) > 1:
                    line = []
                    for value in attributeVariableValue:
                        # if the value is boolean, convert it to LDAP acceptable format
                        if attributeVariableList[2] == "boolean":
                            if value == "t":
                                value = "TRUE"
                            else:
                                value = "FALSE"
                        elif attributeVariableList[2] == "password":
                            if value == "":
                                password = utilityObject.GeneratePassword(config)
                                encryptPassword = md5.new(password).digest()
                                attributeVariableValue = '{md5}' + base64.b64encode(encryptPassword)
                            else:
                                value = '{md5}' + base64.b64encode(value)
                        try:
                            newLine = str(splitOnColon[0]) + ": " + value
                        except:
                            newLine = str(splitOnColon[0]) + ": "
                            
                        line.append(newLine)
                else:
                    if type(attributeVariableValue) is ListType:
                        if attributeVariableValue == []:
                            line = str(splitOnColon[0]) + ": "
                        else:
                            line = str(splitOnColon[0]) + ": " + str(attributeVariableValue[0])
                    else:
                        if attributeVariableValue == "":
                            line = str(splitOnColon[0]) + ": "
                        else:
                            line = str(splitOnColon[0]) + ": " + str(attributeVariableValue)

        return line


    def SplitLdifIntoPythonAttributesList(self, config, utilityObject, objectClassPrefix, objectName, baseDn, ldifFile):
        """ take th`e contents of the ldif file, and create a Python list from them """
        objectAttributes = []
        # now generate the attributes list

        #####DEBUGGING
        if config['General']["debugLevel"] == '5':
            print "ldifFile == ", ldifFile
            print "type(ldifFile) == ", type(ldifFile)

        # generate attributes from ldif (first replace the variables if found)
        for line in ldifFile:
            if line != "":
                # remove the newline character
                if line[-1] == "\n":
                    line = line[:-1]

                #####DEBUGGING
                if config['General']["debugLevel"] == '5':
                    print "line.find([)  == ", line.find("[")
                    import pdb; pdb.set_trace()
                    
                # does the line contain a variable (searching for variable character "[" )
                # line.find() will return -1 if there is no match
                isVariable = line.find("[")

                # remove the variable markers
                if isVariable != -1:
                    isDn = line.find("dn:")
                    isObjectClass = line.find(objectClassPrefix)
                    if isDn != -1:
                        #####DEBUGGING
                        if config['General']["debugLevel"] == '5':
                            import pdb; pdb.set_trace()

                        dn = objectClassPrefix + "=" + objectName + "," + baseDn
                    elif isObjectClass != -1 and objectName != "":
                        splitOnColon = line.split(':')
                        objectAttributes.append( (splitOnColon[0], objectName) )
                    else:    
                        # search/replace variables within the line
                        newLine = self.ReplaceLdifVariables(config, utilityObject, line, baseDn)

                        #####DEBUGGING
                        if config['General']["debugLevel"] == '5':
                            print "newLine == ", newLine
                            import pdb; pdb.set_trace()
                        
                        if type(newLine) is ListType:
                            for l in newLine:
                                splitOnColon = l.split(':')
                                if splitOnColon[0] != "dn":
                                    if len(splitOnColon) == 1:
                                        splitOnColon.append("")
                                    else:      
                                        objectAttributes.append( (splitOnColon[0], splitOnColon[1].strip()) )
                                else:
                                    # dn = objectClassPrefix + "=" + splitOnColon[1].strip()
                                    dn = splitOnColon[1].strip()
                        else:
                            splitOnColon = newLine.split(':')
                            if splitOnColon[0] != "dn":
                                if len(splitOnColon) == 1:
                                    splitOnColon.append("")
                                else:      
                                    objectAttributes.append( (splitOnColon[0], splitOnColon[1].strip()) )
                            else:
                                # dn = objectClassPrefix + "=" + splitOnColon[1].strip()
                                dn =  splitOnColon[1].strip()
                        
                else:
                    splitOnColon = line.split(':')
                    if splitOnColon[0] != "dn":
                        if len(splitOnColon) == 1:
                            splitOnColon.append("")
                        else:    
                            objectAttributes.append( (splitOnColon[0], splitOnColon[1].strip()) )
                    else:
                        # dn = objectClassPrefix + "=" + splitOnColon[1].strip()
                        dn = splitOnColon[1].strip()
                                            
            #####DEBUGGING
            if config['General']["debugLevel"] == '5':
                print "line == ", line
                print "splitOnColon == ", splitOnColon

        objectAttributes.insert(0, dn)
        
        return objectAttributes





    def LdapAddRemoveOU(self, config, utilityObject):
        """ Creates a group at the specified level """
        ## DEBUGGING
        if config['General']["debugLevel"] == '5':
            import pdb; pdb.set_trace()
            
        print "\nAdd/Remove LDAP organizationalUnit\n"

        print "This tool will help you to Add/Remove an organizationalUnit, or OU, under "
        print "the correct container. First, we will need to decide where to create/remove "
        print "the OU.  To do this, please browse to the location you would like to "
        print "create/remove the OU: \n"

        # Search or navigate tree to get to group for adding/removing member
        baseDn = self.LdapSearchInterface(config, utilityObject)

        ## DEBUGGING
        if config['General']["debugLevel"] == '5':
            print "baseDn == ", baseDn
            print "len(baseDn) == ", len(baseDn)

        # set the baseDn by the type of object it is
        if type(baseDn) is StringType:
            pass
        elif type(baseDn) is TupleType:
            baseDn = baseDn[0]
        elif type(baseDn) is ListType:
            baseDn = baseDn[0]
            if type(baseDn) is TupleType:
                # check to see if baseDn is a list with nested tuple           
                baseDn = baseDn[0]

        # test to see if baseDn is empty (which means the user 'q')
        if baseDn != '':
            # Do you want to add/remove current or children?
            addRemoveCurrent = raw_input('Add/Remove [d]istinguished name (printed above), or [c]hild? [ ')
            # Do you want to add or remove these groups
            addRemove = raw_input('[a]dd/[r]emove organizationalUnit? [a] ')
            if addRemove == "":
                addRemove = "a"

            # print header for getting the organizationUnit id
            print "\nNext, we need the name of the organizationalUnit(s) that we would like "
            print "to add/remove. You can enter as many organizationalUnits as you would like."
            print ""
            print "Press 'q' to finish adding organizationalUnits\n"

            # set text for prompt
            objectName = "OrganizationUnit Name? (q => finish) [q] "
            # grab single/multiple groupNames
            ouNameList = utilityObject.GetObjectId(config, objectName)

            # check addRemove to see if we are going to add/remove a group
            if addRemove == 'a':
                # Example - this code will create an object of the type OU.
                """
                [('ou=web,ou=CentWeb,ou=Applications,o=erikin',
                {'objectClass': ['top', 'organizationalUnit', 'ndsLoginProperties', 'ndsContainerLoginProperties'],
                 'ou': ['web'],
                 'ACL': ['2#entry#ou=web,ou=CentWeb,ou=Applications,o=erikin#loginScript',
                 '2#entry#ou=web,ou=CentWeb,ou=Applications,o=erikin#printJobConfiguration']})]
                """
                ## DEBUGGING
                if config['General']["debugLevel"] == '5':
                    print "ouNameList == ", ouNameList
                    print "len(ouNameList) == ", len(ouNameList)

                for ou in ouNameList:
                    aclValue = "2#entry#ou=" + ou + "," + str(baseDn) + "#loginScript"
                    aclValue2 = "2#entry#ou=" + ou + "," + str(baseDn) + "#printJobConfiguration"
                    attrs = []
                    attrs.append( ("objectClass","top") )
                    attrs.append( ("objectClass","organizationalUnit") )
                    attrs.append( ("objectClass","ndsLoginProperties") )
                    attrs.append( ("objectClass","ndsContainerLoginProperties") )
                    attrs.append( ("ou",ou) )
                    attrs.append( ("ACL",aclValue) )
                    attrs.append( ("ACL",aclValue2) )
                    if config['General']["debugLevel"] == '5':
                        print "addRemove == 'a'"
                        print "baseDn == ", baseDn
                        # print "baseDn[0] == ", baseDn[0]
                        # print "baseDn[1] == ", baseDn[1]

                    #if not baseDn[0]
                    dn = "ou=" + ou + "," + str(baseDn)
                    if config['General']["debugLevel"] == '5':
                        print "dn == ", dn

                    # create the object
                    self.LdapCreateObject(config, dn, attrs)
            elif addRemove == 'r':
                for ou in ouNameList:
                    dn = str(baseDn)
                    if config['General']["debugLevel"] == '5':
                        print "addRemove == 'r'"
                        print "str(dn) == " + str(dn)
                    self.LdapDeleteObject(config, dn)


    def LdapAddRemoveGroup(self, config, utilityObject):
        """ Creates a group at the specified level """
        # connect to the server and bind
        # ldapConn = self.Connect(config)

        print "Add/Remove LDAP group\n"

        print "This tool will help you to Add/Remove a group under the correct container"
        print "We will first need to decide where to create the group.  To do this, "
        print "please choose from the following list of virtual host DNs: \n"

        # Search or navigate tree to get to group for adding/removing member
        baseDn = self.LdapSearchInterface(config, utilityObject)

        ## DEBUGGING
        if config['General']["debugLevel"] == '5':
            print "baseDn == ", baseDn

        # set the baseDn by the type of object it is
        if type(baseDn) is StringType:
            pass
        elif type(baseDn) is TupleType:
            baseDn = baseDn[0]
        else:
            # check to see if baseDn is a list with nested tuple           
            baseDn = baseDn[0][0]

        ## DEBUGGING
        if config['General']["debugLevel"] == '5':
            print "baseDn (after manipulation) == ", baseDn

        # test to see if baseDn is empty (which means the user 'q')
        if baseDn != '':
            # Do you want to add or remove these groups
            addRemove = raw_input('Add/Remove Group? (a => add, r = remove) ')

            # Print header for getting the group id
            print "\nNext, we need the name of the group(s) that we would like to add."
            print "You can enter as many groups as you would like."
            print ""
            print "Press 'q' to finish adding groups\n"
            
            # set text for prompt
            objectName = "Group Name? (ie managers) (q => finish) [q] "
            # grab single/multiple groupNames
            groupNameList = utilityObject.GetObjectId(config, objectName)

            # check addRemove to see if we are going to add/remove a group
            if addRemove == 'a':                    
                for group in groupNameList:
                    # Example - this code will create an object of the type posixAccount.
                    attrs = []
                    attrs.append( ("objectClass","top") )
                    attrs.append( ("objectClass","posixGroup") )
                    attrs.append( ("objectClass","groupOfNames") )
                    attrs.append( ("objectClass","uamPosixGroup") )
                    # attrs.append( ("member","") )
                    attrs.append( ("gidNumber","50001") )
                    attrs.append( ("cn", group) )
                    ## DEBUGGING
                    if config['General']["debugLevel"] == '5':
                        print "baseDn[0] == ", baseDn[0]
                        print "baseDn[0][0] == ", baseDn[0][0]
                        print "baseDn[0][0][0:3] == ", baseDn[0][0][0:3]
                        print "len(baseDn[0][0]) == ", len(baseDn[0][0])
                        print "attrs == ", attrs
                        
                    dn = "cn=" + group + "," + str(baseDn)

                    # self.LdapCreateObject(ldapConn, dn, attrs)
                    self.LdapCreateObject(config, dn, attrs)
            elif addRemove == 'r':
                for group in groupNameList:
                    dn = "cn=" + group + "," + str(baseDn)
                    if config['General']["debugLevel"] == '5':
                        print "dn == " + str(dn)
                    # self.LdapDeleteObject(ldapConn, dn)
                    self.LdapDeleteObject(config, dn)

 



    def LdapCopyObjectInterface(self, config, utilityObject):
        """ Creates copy ldap object to a new location """

        print "\nCopy LDAP Objects\n"

        print "This tool will help you to LDAP objects to a new location. "
        print "First, we will need to find the location of the originating object."
        print "To do this, please browse, or search, for the location you would like to copy:"
        print
        print "Example: "
        print "If you want to copy: "
        print "cn=talons,ou=orgs_erikin_com,ou=web,ou=CentWeb,ou=Applications,o=erikin"
        print "To: "
        print "cn=talons,ou=web3_erikin_com,ou=web,ou=CentWeb,ou=Applications,o=erikin"
        print
        print "You should search for the following here:"
        print "cn=talons"
        print


        # Search or navigate tree to get to group for adding/removing member
        origBaseDn = self.LdapSearchInterface(config, utilityObject)

        # test to see if the user quit
        if origBaseDn == "":
            origBaseDn = []
            
        # set the origBaseDn by the type of object it is
        if type(origBaseDn) is StringType:
            pass
        elif type(origBaseDn) is TupleType:
            origBaseFullDn = origBaseDn[0]
            cn = origBaseDn[1]["cn"][0]
        elif type(origBaseDn) is ListType:
            try:
                origBaseDn = origBaseDn[0]
                if type(origBaseDn) is TupleType:
                    # check to see if origBaseDn is a list with nested tuple 
                    cn = origBaseDn[1]["cn"][0]
                    origBaseFullDn = origBaseDn[0]
                    
            except:
                print "The LDAP Object you are searching for doesn't exist."
                print "Please try again."
                origBaseFullDn = ""
                
        ## DEBUGGING
        if config['General']["debugLevel"] == '5':
            print "origBaseDn == ", origBaseDn
            print "origBaseFullDn == ", origBaseFullDn
            print "len(origBaseDn) == ", len(origBaseDn)
            try:
                print "origBaseDn[1][cn][0] == ", origBaseDn[1]["cn"]
            except:
                print "origBaseDn[1][cn][0] doesn't exist"

        # test to see if origBaseDn is empty (which means the user 'q')
        if origBaseFullDn != '':
            # Do you want to delete this object after copying it to the new location?
            print
            print "The current LDAP library, or eDirectory, does not support a copy command"
            print "So this operation will only move the object and delete the old object."
            print
#             addRemoveCurrent = raw_input('Delete old object after copying? (y/[n]) ')
#             if addRemoveCurrent == "":
#                 addRemoveCurrent = "n"

#             # set delolddn based on addRemoveCurrent
#             if addRemoveCurrent == "n":
#                 delolddn = 0
#             else:
#                delolddn = 1
            delolddn = 1

            # rename object in current parentdn?
            renameInSameLocation = raw_input("[r]ename object, or [m]ove it do a different location? ([r]/m) ")
            if renameInSameLocation == "" or renameInSameLocation != "m":
                renameInSameLocation = "r"

            if renameInSameLocation != "r":
                # ask for the location of and name of the newdn
                print "This tool will help you to LDAP objects to a new location. "
                print "Next, we will need to find the location for the destination object."
                print "To do this, please browse, or search, for the parent location to "
                print "which you would like the object copied:"
                print
                print "Example: "
                print "If you want to copy: "
                print "cn=talons,ou=orgs_erikin_com,ou=web,ou=CentWeb,ou=Applications,o=erikin"
                print "To: "
                print "cn=talons,ou=web3_erikin_com,ou=web,ou=CentWeb,ou=Applications,o=erikin"
                print
                print "You should search for the following here:"
                print "ou=web3_erikin_com"
                print


                # Search or navigate tree to get to group for adding/removing member
                newParentDn = self.LdapSearchInterface(config, utilityObject)

                # test to see if the user quit w/out searching
                if newParentDn  == "":
                    newParentDn = []

                # set the newParentDn by the type of object it is
                if type(newParentDn) is StringType:
                    pass
                elif type(newParentDn) is TupleType:
                    newParentFullDn = newParentDn[0]
                elif type(newParentDn) is ListType:
                    try:
                        newParentFullDn = newParentDn[0][0]
                        if type(newParentDn) is TupleType:
                            # check to see if newParentFullDn is a list with nested tuple
                            newParentFullDn = newParentFullDn[0]
                    except:
                        print "The LDAP Object you are searching for doesn't exist"
                        print "Please try again."
                        newParentFullDn = ""
            else:
                newParentDn = None
                newParentFullDn = None

            ## DEBUGGING
            if config['General']["debugLevel"] == '5':
                print "newParentDn == ", newParentDn
                print "newParentFullDn == ", newParentFullDn
                try:
                    print "len(newParentDn) == ", len(newParentDn)
                except:
                    print "newParentDn has no length"
                    
            if newParentFullDn != "" or newParentFullDn is not None:
                # keep existing object name?
                print
                print "Current Object Name: "
                print cn
                print
                if renameInSameLocation == "m":
                    keepExistingObjectName = raw_input("Keep existing object name? ([y]/n) ")
                    if keepExistingObjectName == "":
                        keepExistingObjectName = "y"
                elif renameInSameLocation == "r":
                    keepExistingObjectName = raw_input("Keep existing object name? (y/[n]) ")
                    if keepExistingObjectName == "":
                        keepExistingObjectName = "n"
                        
                if keepExistingObjectName == "y":
                    newdn = "cn=" + cn
                else:
                    newdn = ""
                    while newdn == "":
                        newdn = raw_input("New Object Name? ")
                        newdn = "cn=" + newdn

                ## DEBUGGING
                if config['General']["debugLevel"] == '5':
                    print "cn == ", cn
                    print "newdn == ", newdn
                    print "delolddn == ", delolddn
                    print "type(delolddn) == ", type(delolddn)
                ## DEBUGGING
                if config['General']["debugLevel"] == '5':
                    import pdb; pdb.set_trace()

                # copy the object from origBaseFullDn to cn + newParentFullDn
                self.LdapCopyObject(config, origBaseFullDn, newdn, newParentFullDn, delolddn) 

    def LdapAddUser(self, config, utilityObject):
        """ Add/Remove a user to a LDAP group """
        ## add by database or by user?
        userOrGroup = raw_input("Add by [u]ser/[g]roup, or [q]uit? [g] ")
        if userOrGroup == "":
            userOrGroup = "g"

        # create the connection to the database
        # conn = self.Connect(config)

        # if userOrGroup == 'u', get a list of users to add
        if userOrGroup == 'u':
            self.LdapAddRemoveUserToGroup(config, utilityObject)
        elif userOrGroup == 'g':
            self.LdapAddRemoveGroupToUser(config, utilityObject)
        else:
            print "\nInvalid command.  Please re-enter your choice.\n"

        # unbind from the server
        # self.Disconnect(conn)



    def LdapAddRemoveUserToGroup(self, config, utilityObject):
        """ adds a user to a group at the specified level """
        print "Add/Remove a User in a LDAP group\n"

        print "This tool will help you to add/remove a user to an existing LDAP group"
        print "We will first need to decide which group to add this user to."
        print "(Groups are designated by a prefix of 'cn=')"
        print "To do this, please choose from the following list of virtual hosts: \n"

        # Search or navigate tree to get to group for adding/removing member
        baseDn = self.LdapSearchInterface(config, utilityObject)
        
        ## DEBUGGING
        if config['General']["debugLevel"] == '5':
            print "len(baseDn) == ", len(baseDn)
            print "baseDn == ", baseDn
            
        # set the baseDn by the type of object it is
        if type(baseDn) is StringType:
            pass
        elif type(baseDn) is TupleType:
            baseDn = baseDn[0]
        elif type(baseDn) is ListType:
            baseDn = baseDn[0]
            if type(baseDn) is TupleType:
                # check to see if baseDn is a list with nested tuple           
                baseDn = baseDn[0]

        ## DEBUGGING
        if config['General']["debugLevel"] == '5':
            try:
                for base in baseDn:
                    print "base (before adding euid) == ", base
            except:
                print "There are not multiple DNs returned"
            print "baseDn (before adding euid) == ", baseDn
            print "len(baseDn) == ", len(baseDn)

        # Do you want to add or remove these users
        addRemove = raw_input('[a]dd/[r]emove User? [a] ')
        if addRemove == "":
            addRemove = "a"
            
        # test to see if baseDn is empty (which means the user 'q')
        if baseDn != '':
            # Print header for getting the user id
            print "\nNext, we need the euid of the user(s) that we would like to add."
            print "You can enter as many euids as you would like."
            print ""
            print "Press 'q' to finish adding euids\n"

            # set text for prompt
            objectName = "User's Euid? (q => finish) [q] "
            
            userNameList = utilityObject.GetObjectId(config, objectName)
                
            for euid in userNameList:                    
                setUser = config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["ldapUserAttr"] + "=" + euid + "," + config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["userBaseDN"]
                if config['General']["debugLevel"] == '5': 
                    print "setUser == ", setUser

                attrs = []

                # check addRemove to see if we want to add or remove the user
                if addRemove == 'a':
                    mod_type = ldap.MOD_ADD
                elif addRemove == 'r':
                    mod_type = ldap.MOD_DELETE

                attrs.append( (mod_type, "member", setUser) )

                # try:
                #    dn = str(baseDn[0][0])
                #except:
                #    dn = str(baseDn[0])
                dn = str(baseDn)
                if config['General']["debugLevel"] == '5':
                    print "baseDn == ", baseDn
                    print "baseDn[0] == ", baseDn[0]
                    print "user dn == ", dn
                    print "user attrs == ", attrs

                self.LdapModifyObject(config, dn, attrs)
                # end of individual user config



    def LdapAddRemoveGroupToUser(self, config, utilityObject):
        """ adds a user to multiple groups """
        ## DEBUGGING
        if config['General']["debugLevel"] == '10':
            import pdb; pdb.set_trace()
            
        # print "Add/Remove a User in a LDAP group\n"

        print "This tool will help you to add/remove a user to an multiple LDAP group"
        print "We will first need to decide which groups to add this user to."
        print "(Groups are designated by a prefix of 'cn=')"
        print ""
        print "Press 'q' to finish adding Groups\n"

        # set text for prompt
        groupName = "Group Name? (q => finish) [q] "
        # grab single/multiple Names
        nameList = utilityObject.GetObjectId(config, groupName)

        groupList = []
        # for every item in groupList add a list of users
        for name in nameList:
            # set the searchType to group
            searchType = 0
            # set filter to name
            filter = "cn=" + name
            # do search
            try:
                filterDict = self.LdapSearch(config, filter, searchType)
                
                # print out search in tabular format            
                # try:
                baseDn = self.LdapSearchPrint(config, utilityObject, filterDict, filter)

                # set the baseDn by the type of object it is
                if type(baseDn) is StringType:
                    pass
                elif type(baseDn) is TupleType:
                    baseDn = baseDn[0]
                elif type(baseDn) is ListType:
                    baseDn = baseDn[0]
                    if type(baseDn) is TupleType:
                        # check to see if baseDn is a list with nested tuple           
                        baseDn = baseDn[0]

                ## DEBUGGING
                if config['General']["debugLevel"] == '5':
                    try:
                        for base in baseDn:
                            print "base (before adding euid) == ", base
                    except:
                        print "There are not multiple DNs returned"
                    print "baseDn (before adding euid) == ", baseDn
                    print "len(baseDn)adsf == ", len(baseDn)

                # Do you want to add or remove these users
                addRemove = raw_input('[a]dd/[r]emove User? [a] ')
                if addRemove == "":
                    addRemove = "a"
                    
                # test to see if baseDn is empty (which means the user 'q')
                if baseDn != '':
                    # Print header for getting the user id
                    print "\nNext, we need the euid of the user(s) that we would like to add."
                    print "You can enter as many euids as you would like."
                    print ""
                    print "Press 'q' to finish adding euids\n"

                    # set text for prompt
                    objectName = "User's Euid? (q => finish) [q] "

                    userNameList = utilityObject.GetObjectId(config, objectName)
                
                    for euid in userNameList:                    
                        setUser = config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["ldapUserAttr"] + "=" + euid + "," + config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["userBaseDN"]
                        if config['General']["debugLevel"] == '5': 
                            print "setUser == ", setUser

                        attrs = []
                
                        # check addRemove to see if we want to add or remove the user
                        if addRemove == 'a':
                            mod_type = ldap.MOD_ADD
                        elif addRemove == 'r':
                            mod_type = ldap.MOD_DELETE

                        attrs.append( (mod_type, "member", setUser) )

                        # try:
                        #    dn = str(baseDn[0][0])
                        #except:
                        #    dn = str(baseDn[0])
                        dn = str(baseDn)
                        if config['General']["debugLevel"] == '5':
                            print "baseDn == ", baseDn
                            print "baseDn[0] == ", baseDn[0]
                            print "user dn == ", dn
                            print "user attrs == ", attrs

                        self.LdapModifyObject(config, dn, attrs)
                        # end of individual user config
            except:
                print "The LDAP group ", name, " doesn't exist.  Continuing with next group.\n"
                continue


    def NavigateTree(self, config, groupadd=0, userAdd=0):
        """ Navigate through an LDAP container """
        ## DEBUGGING
        if config['General']["debugLevel"] == '5':
            print config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["containerBaseDn"]
            import pdb
            pdb.set_trace()
        parent = config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["containerBaseDn"]
        
        # connect to the server and bind
        ldapConn = self.Connect(config)
        
        # do a simple search to test
        getOrganizationalUnit = ldapConn.search_s( config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["containerBaseDn"], ldap.SCOPE_ONELEVEL, "objectclass=*")

        # unbind from the server
        self.Disconnect(ldapConn)

        ## DEBUGGING
        if config['General']["debugLevel"] == '5':
            print "getOrganizationUnit == ", getOrganizationalUnit
            
        # get number of orgunits in list
        length = len(getOrganizationalUnit)
        # initialize some iterators
        objectValue = 0
        stopBrowse = 0
        
        # initialize list to hold new values
        objectList = []
        getOrganizationalUnit2 = ( config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["containerBaseDn"], {'': ''})
        while stopBrowse != 'q':
            for name in getOrganizationalUnit:
                #print name[0]
                print "(%d) %s " % (objectValue, name[0])
                objectList.append( (objectValue, name[0]) ) 

                objectValue += 1
                if objectValue == length:
                    print "(" + str(objectValue) + ") Place/Remove Entry At Current Level"
                    print "(s### => select entry, q => quit): \n"

            stopBrowse = raw_input("Which Entry Would You Like To Choose? ")

            # check to see if the first letter is an s (to select entry)
            if stopBrowse[:1] == 's':
                name = objectList[int(stopBrowse[1:])][1]
                break
                                  
            # set stopBrowse if stopBrowse != 'q'
            if stopBrowse == 'q':
                stopBrowse = 'stop'
                # user has typed 'q'
                name = ''
                break

            # if the user didn't type 'q' and
            # they have chosen another choice besides
            # 'place at current level', then execute this.
            if stopBrowse != 'stop' and int(stopBrowse) != objectValue:
                ## DEBUGGING
                if config['General']["debugLevel"] == '5':
                    print "stopBrowse[:1] != s### and stopBrowse != 'q'"
                    
                # do a simple search to test
                objectListItem = int(stopBrowse)
                ## DEBUGGING
                if config['General']["debugLevel"] == '5':
                    print "objectListItem == ", objectListItem
                
                # if it is a group set name = getOrganizationalUnit and break
                if objectList[objectListItem][1][0:3] == 'cn=' and userAdd == 0:
                    setIsGroup = 1
                    #name = getOrganizationalUnit[objectListItem]
                    name = getOrganizationalUnit[int(stopBrowse)]
                    break
                elif objectList[objectListItem][1][0:3] == 'cn=' and userAdd == 1:
                    name = getOrganizationalUnit[int(stopBrowse)]
                    break
                
                # set getOrganizationalUnit2 to the current getOrganizationalUnit
                # This is so that it is easier to grab the
                # baseDn when we break out of this loop
                getOrganizationalUnit2 = getOrganizationalUnit
                parent = getOrganizationalUnit[int(stopBrowse)]

                # connect to the server and bind
                ldapConn = self.Connect(config)

                # get the new value for the baseDn
                getOrganizationalUnit = ldapConn.search_s(objectList[objectListItem][1], ldap.SCOPE_ONELEVEL, "objectclass=*")

                # unbind from the
                self.Disconnect(ldapConn)

                # check to see if getOrganizationalUnit is an empty list
                if len(getOrganizationalUnit) == 0:
                    name = getOrganizationalUnit2[int(stopBrowse)]
                    print "We're Sorry, But There Are No Objects In This OU."
                    break
                
                #reset our value
                objectList = []
                objectValue = 0
                length = len(getOrganizationalUnit)

            # if stopBrowse == objectValue, then the user wants
            # to create the folder at the current level
            elif int(stopBrowse) == objectValue:
                ## DEBUGGING
                if config['General']["debugLevel"] == '5':
                    print "stopBrowse == ", stopBrowse
                    print "objectValue == ", objectValue
                    print "length == ", length
                    print "groupadd == ", groupadd
                    print "parent == ", parent
                    print "We are creating an object at this level, so return the parent DN"

                # set name = to parent DN
                if groupadd == 1:
                    name = parent
                else:
                    name = parent
                break

        #we want to add the group here
        ## DEBUGGING
        if config['General']["debugLevel"] == '5':
            print name
            
        return name

    def CreateOU(self, config, vHost):
        """ Allows a remote call to create an ou at the specified level
        Reference to Webcontrol.CreateVHost()
        """
        # create vHost OU
        aclValue = "2#entry#ou=" + vHost + "," + str(config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["containerBaseDn"]) + "#loginScript"
        aclValue2 = "2#entry#ou=" + vHost + "," + str(config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["containerBaseDn"]) + "#printJobConfiguration"
        ouAttrs = []
        ouAttrs.append( ("objectClass","top") )
        ouAttrs.append( ("objectClass","organizationalUnit") )
        ouAttrs.append( ("objectClass","ndsLoginProperties") )
        ouAttrs.append( ("objectClass","ndsContainerLoginProperties") )
        ouAttrs.append( ("ou",vHost) )
        ouAttrs.append( ("ACL",aclValue) )
        ouAttrs.append( ("ACL",aclValue2) )
        dn = "ou=" + vHost + "," + str(config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["containerBaseDn"])

        ## DEBUGGING
        if config['General']["debugLevel"] == '5':
            print "ouAttrs == ", ouAttrs
            print "dn == ", dn

        # connect to the server and bind
        #ldapConn = self.Connect(config)

        create = self.LdapCreateObject(config, dn, ouAttrs)

        # unbind from the server
        #self.Disconnect(ldapConn)

        return create



    def CreateepSite(self, config, vHost):
        """ Allows a remote call to create an ou at the specified level
        Reference to Webcontrol.CreateVHost()
        """
        # create epSite
        aclValue = "2#entry#ou=" + vHost + "," + str(config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["containerBaseDn"]) + "#loginScript"
        aclValue2 = "2#entry#ou=" + vHost + "," + str(config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["containerBaseDn"]) + "#printJobConfiguration"
        ouAttrs = []
        ouAttrs.append( ("objectClass","top") )
        ouAttrs.append( ("objectClass","organizationalUnit") )
        ouAttrs.append( ("objectClass","ndsLoginProperties") )
        ouAttrs.append( ("objectClass","ndsContainerLoginProperties") )
        ouAttrs.append( ("ou",vHost) )
        ouAttrs.append( ("ACL",aclValue) )
        ouAttrs.append( ("ACL",aclValue2) )
        dn = "ou=" + vHost + "," + str(config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["containerBaseDn"])

        ## DEBUGGING
        if config['General']["debugLevel"] == '5':
            print "ouAttrs == ", ouAttrs
            print "dn == ", dn

        # connect to the server and bind
        #ldapConn = self.Connect(config)

        create = self.LdapCreateObject(config, dn, ouAttrs)

        # unbind from the server
        #self.Disconnect(ldapConn)

        return create


    def CreateGroup(self, config, vHostWebroot, group):
        """ Creates a group under a specific container """
        groupAttrs = self.GroupAttrs(config, group)
        dn = self.CreateGroupDN(config, vHostWebroot, group)
        
        create = self.LdapCreateObject(config, dn, groupAttrs)

        return create

    def UserAttrs(self, config, vHostWebroot, user):
        """ Add user to group membership """
        mod_type = ldap.MOD_ADD
        userAttrs = []
        setUser = config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["ldapUserAttr"] + "=" + user + "," + config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["userBaseDN"]
        userAttrs.append( (ldap.MOD_ADD, "member", setUser) )

        if config['General']["debugLevel"] == '5':
            print userAttrs
            print setUser
            
        return userAttrs
    
    def GroupAttrs(self, config, group):
        # Example - this code will create an object of the type posixAccount.
        attrs = []
        attrs.append( ("objectClass","top") )
        attrs.append( ("objectClass","posixGroup") )
        attrs.append( ("objectClass","groupOfNames") )
        attrs.append( ("objectClass","uamPosixGroup") )
        attrs.append( ("gidNumber","50001") )
        attrs.append( ("cn", group) )

        if config['General']["debugLevel"] == '5':
            print attrs

        return attrs

    def CreateGroupDN(self, config, vHostWebroot, group):
        dn = "cn=" + group + ",ou=" + vHostWebroot + "," + config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["containerBaseDn"]
        if config['General']["debugLevel"] == '5':
            print "CreateGroupDN.dn == ", dn
            
        return dn
    
    def LdapCreateObject(self, config, dn, attrs):
        """ Creates the object in the ldap server """
        try:
            # connect to the server and bind
            ldapConn = self.Connect(config)

            ldapConn.add_s(dn, attrs)
            
            # unbind from the server
            self.Disconnect(ldapConn)
        except:
            print "Failed to add the object with the following error:", sys.exc_info()[0]

    def LdapModifyObject(self, config, dn, userAttrs):
        """ Modifies the object in the ldap server """
        try:
            # connect to the server and bind
            ldapConn = self.Connect(config)
            
            ldapConn.modify_s(dn, userAttrs)

            # unbind from the server
            self.Disconnect(ldapConn)
        except:
            print "Failed to modify the object with the following error:", sys.exc_info()[0]
        

    def LdapCopyObject(self, config, origBaseFullDn, newdn, newParentDn, delolddn=0):
        """ Creates the object in the ldap server """
        try:
            # connect to the server and bind
            ldapConn = self.Connect(config)
            
            ldapConn.rename_s(origBaseFullDn, newdn, newParentDn, delolddn)

            # unbind from the server
            self.Disconnect(ldapConn)
        except:
            print "Failed to modify the object with the following error:", sys.exc_info()[0]


    def LdapDeleteObject(self, config, dn):
        """ Deletes an object from the ldap server """
        try:
            # connect to the server and bind
            ldapConn = self.Connect(config)
            
            ldapConn.delete_s(dn)

            # unbind from the server
            self.Disconnect(ldapConn)
        except:
            print "Failed to delete the object with the following error:", sys.exc_info()[0]


    def LdapSearch(self, config, filter, searchType = '1'):
        """ perform search on ldap server """
        #
        # searchType = '0' -> Searching for OU or group        
        # searchType = '1' -> Searching for user object
        
        #
        # do a simple search to test
        ## DEBUGGING
        if config['General']["debugLevel"] == '5':
            print "searchType == ", searchType
            print "type(searchType) == ", type(searchType)

        searchDnList = []
        if searchType == '1':
            searchDnList.append( config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["userBaseDN"] )
            searchDnList.append( config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["containerNewUserBaseDn"] )
        else:
            searchDnList.append( config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["containerBaseDn"] )
        ## DEBUGGING
        if config['General']["debugLevel"] == '5':
            print "searchDnList == ", searchDnList
            print "filter == ", filter
            #import pdb; pdb.set_trace()
            
        try:
            # connect to the server and bind
            ldapConn = self.Connect(config)

            newFilterList = []
            for searchDn in searchDnList:
                filterDict = ldapConn.search_st(searchDn, ldap.SCOPE_SUBTREE, filter, timeout=10)
                ## DEBUGGING
                if config['General']["debugLevel"] == '5':
                    print "searchDn == ", searchDn
                    print "filterDict == ", filterDict
                    print "len(filterDict) == ", len(filterDict)
                if filterDict != []:
                    newFilterList.append( filterDict )
                ## DEBUGGING
                if config['General']["debugLevel"] == '5':
                    print "newFilterList == ", newFilterList

            ## DEBUGGING
            if config['General']["debugLevel"] == '5':
                print "filterDict == ", filterDict
                print "newFilterList == ", newFilterList
                print "len(newFilterList) == ", len(newFilterList)
                print "type(newFilterList) == ", type(newFilterList)
                print "newFilterList[0] == ", newFilterList[0]
                print "type(newFilterList[0]) == ", type(newFilterList[0])
                print "newFilterList[0][0] == ", newFilterList[0][0]
                print "type(newFilterList[0][0]) == ", type(newFilterList[0][0])

                # import pdb; pdb.set_trace()

            # split the filterDict (which is a poorly named list :P )
            # and move all two-dimensional entries into the first dimension
            if len(newFilterList) > 0:
                newList = []
                for i in range(0, len(newFilterList) ):
                    entry = newFilterList[i]
                    if len(entry) > 1:
                        for subi in range(0, len(entry) ):
                            ## DEBUGGING
                            if config['General']["debugLevel"] == '5':
                                print "entry[subi] == ", entry[subi]

                            subentry = entry[subi]
                            newList.append( subentry )
                    else:
                        ## DEBUGGING
                        if config['General']["debugLevel"] == '5':
                            print "entry[0] == ", entry[0]
                    
                        newList.append( entry[0] )
                ## DEBUGGING
                if config['General']["debugLevel"] == '5':
                    print "newList == ", newList
                    print "filterDict == ", filterDict
                    
                filterDict = newList

            else:
                if config['General']["debugLevel"] == '5':
                    print "filterDict (all lists are in first dimension) == ", filterDict

                filterDict = filterDict
                if config['General']["debugLevel"] == '5':
                    print "filterDict (all lists are in first dimension) == ", filterDict

            #filterDict = ldapConn.search(searchDn, ldap.SCOPE_SUBTREE, filter)


            # unbind from the server
            self.Disconnect(ldapConn)

            ## DEBUGGING
            if config['General']["debugLevel"] == '5':
                print "filterDict == ", filterDict
                print "type(filterDict) == ", type(filterDict)
            
            return filterDict
        except:
            print "Failed to perform the LDAP search the following error:", sys.exc_info()[0]
            


    def LdapSearchPrint(self, config, utilityObject, filterDict, filter):
        """ print search results in tabular format """
        # test to see if more than one result was returned
        viewAll = 'n'
        while viewAll == 'n':
            ## DEBUGGING
            if config['General']["debugLevel"] == '5':
                print "filterDict == ", filterDict
            if len(filterDict) > 1:
                print ""
                for name in filterDict:
                    dn = name[0]
                    print "(" + str(filterDict.index(name)) + ") " + dn
                viewAll = raw_input("\nUser Entry? ([a] => View All, n => Narrow Search, q => quit) ")

                if viewAll == "":
                    viewAll = "a"
                elif viewAll == "q":
                    break

                # now we narrow our search by searching the returned list
                if viewAll == 'n':
                    narrowedSearch = 'n'
                    filter = self.LdapSearchPrompt()
                    # split filter for attr = filter
                    regexpSplitEquals = re.compile(r'[=]')
                    splitAttr = regexpSplitEquals.split(filter)
                    ## DEBUGGING
                    if config['General']["debugLevel"] == '5':
                        print "splitAttr == ", splitAttr
                    # now we use filter to search through the following tuple
                    # ('uid=lla0018,ou=people,o=erikin', {'cn': ['Linda Lynn Anderson'], 'uid': ['lla0018'],
                    # 'objectClass': ['inetOrgPerson', 'erikinPerson', 'organizationalPerson',
                    # 'Person', 'ndsLoginProperties', 'Top', 'arsProperties'], 'sn': ['Anderson'],
                    # 'systemaccess': ['eaglemail', 'enterprise'], 'givenName': ['Linda'], 'euid': ['lla0018']})]
                    index = 0
                    newFilterDict = []
                    newFilterDictIndex = 0
                    for entry in filterDict:
                        # set ldapUserAttrDict to the dictionary in entry
                        ldapUserAttrDict = entry[1]
                        for name, value in ldapUserAttrDict.items():
                            ## DEBUGGING
                            if config['General']["debugLevel"] == '5':
                                print "name == ", name
                                # print "value == ", value
                            # test to see if filter is found in ldapUserAttrDict
                            if name == splitAttr[0]:
                                for id in value:
                                    if id == splitAttr[1]:
                                        ## DEBUGGING
                                        if config['General']["debugLevel"] == '5':
                                            print "filterDict[index] == ", filterDict[index]
                                        newFilterDict.append(filterDict[index])
                                        newFilterDictIndex = newFilterDictIndex + 1
                        index = index + 1
                    filterDict = newFilterDict                
            else:
                try:
                    ## DEBUGGING
                    if config['General']["debugLevel"] == '5':
                        print "index == ", index
                        print "viewAll == ", index
                        print "newFilterDictIndex == ", newFilterDictIndex

                    viewAll = newFilterDictIndex - 1
                    break
                except:
                    break
                
        # change filterDict to single entry if viewAll != 'a'
        if viewAll == 'q' or len(filterDict) == 0:
            pass
        elif viewAll != 'a' and viewAll != 'n':
            filterDict = filterDict[int(viewAll)]
            dn = filterDict[0]
            attr = filterDict[1]
            ## DEBUGGING
            if config['General']["debugLevel"] == '5':
                # print "filterDict[int(viewAll)] == ", filterDict[int(viewAll)]
                print "filterDict == ", filterDict
                print "dn == ", filterDict[0]
                print "attr == ", filterDict[1]

            pdf = raw_input("Print a PDF version? (y/[n]) ")
            if pdf == "":
                pdf = "n"

            if pdf != "y":
                self.LdapSearchPrintFormat(config, utilityObject, filterDict, filter, dn, attr)
            else:
                self.LdapSearchPrintFormat(config, utilityObject, filterDict, filter, dn, attr)
                r = ReportFunc()
                r.LdapSearchPrintFormatPDF(config, utilityObject, filterDict, filter, dn, attr)
        else: 
            # print each entry in filterDict
            pdf = raw_input("Print a PDF version? (y/[n]) ")
            if pdf == "":
                pdf = "n"
            for name in filterDict:
                ## DEBUGGING
                if config['General']["debugLevel"] == '5':
                    print "name == ", name
                dn = name[0]
                attr = name[1]

                self.LdapSearchPrintFormat(config, utilityObject, filterDict, filter, dn, attr)

            if pdf == "y":
                r = ReportFunc()
                r.LdapSearchPrintFormatPDF(config, utilityObject, filterDict, filter)

        return filterDict



    def LdapSearchPrintFormat(self, config, utilityObject, filterDict, filter, dn, attr): 
            
        print "\nfilter is ", filter
        print "---------------------"
        print "dn: " + dn + "\n"

        if attr.has_key('cn'):
            print "                       cn: %s" % attr['cn']
        if attr.has_key('givenName'):
            print "                givenName: %s" % attr['givenName']
        if attr.has_key('mi'):
            print "                       mi: %s" % attr['mi']
        if attr.has_key('sn'):
            print "                       sn: %s" % attr['sn']
        if attr.has_key('euid'):
            print "                     euid: %s" % attr['euid']
        if attr.has_key('uid'):
            print "                      uid: %s" % attr['uid']
        if attr.has_key('idno'):
            print "                     idno: %s" % attr['idno']
        if attr.has_key('college'):
            print "                  college: %s" % attr['college']
        if attr.has_key('role'):
            print "                     role: %s" % attr['role']
        if attr.has_key('birthdate'):
            print "                birthdate: %s" % attr['birthdate']
        # epSite object attributes
        if attr.has_key('siteStatus'):
            print "                Site Live: %s" % attr['siteStatus']
        if attr.has_key('url'):
            print "                 Site URL: %s" % attr['url']
        if attr.has_key('progLang'):
            print "    Programming Languages: %s" % attr['progLang']
        # epForm object attributes
        if attr.has_key('directoryInfo'):
            print "    Directory Information: %s" % attr['directoryInfo']
        if attr.has_key('formMember'):
            print "            Web Form Name: %s" % attr['formMember']
        if attr.has_key('formPurpose'):
            print "      Purpose of Web Form: %s" % attr['formPurpose']
        if attr.has_key('privPolicy'):
            print "Is there a privacy policy? %s" % attr['privPolicy']
        if attr.has_key('recordRetention'):
            print "           Data Retention? %s days" % attr['recordRetention']
        if attr.has_key('registeredBy'):
            print "            Registered By? %s " % attr['registeredBy']
        
        if attr.has_key('member'):
            euidList = []
            for euid in attr['member']:
                splitEuid = re.split(',', euid)
                euidFilter = splitEuid[0]
                euidList.append(euidFilter)
                ## this is causing a lot of extra calls to ldap and slowing long printouts to stdout
                ## need to do a single connect here, instead of multiple connections
                if config['General']["debugLevel"] == '5':
                        print "euidFilter == ", euidFilter
                euidDict = self.LdapSearch(config, euidFilter)
                name = ''
                ## DEBUGGING
                if config['General']["debugLevel"] == '5':
                     print "euidDict == ", euidDict

                if euidDict != None:
                    for euidAttr in euidDict:
                        key = euidAttr[0]
                        value = euidAttr[1]

                        if value.has_key('givenName'):
                            name = value['givenName']
                        if value.has_key('sn'):
                            name = name + value['sn']
                            print " "*19 + "member: %s" % name

            ## DEBUGGING
            if config['General']["debugLevel"] == '5':
                print "euidList == ", euidList
                print "len(euidList) == ", len(euidList)
                print "member: %s" % attr['member']
            if len(euidList) > 0:
                for euid in euidList:
                    if euid != "":
                        splitEuid2 = re.split('=', euid)
                        print " "*21 + "euid: %s" % splitEuid2[1]
                    
        print "---------------------"
        print "\n"


        

    def LdapSearchPrompt(self, ldapsearch=""):
        """ Generate Ldap Search Prompt w/ help """
        help = 'h'
        while help == 'h':
            if ldapsearch == "":
                filter = raw_input("LDAP Search: (b => browse tree, h => help, q => quit) ")
                if filter == 'h':
                    print "\nUser Searches:\n"
                    print "euid=abc1"
                    print "uid=abc2"
                    # print "cn=Firstname*Lastname\n"
                    print "sn=Lastname"
                    print "givenname=Firstname"
                    print "--------------------\n"
                    print "General Object Searches:\n"
                    print "cn=Groupname"
                    print "ou=OrganizationUnit"
                    print "--------------------\n"
                    print "Boolean searches:\n"
                    print "AND:  (&(cn=www)(ou:dn:=www_tcet_erikin_com))"
                    print "\t Searches for a cn=www (group) AND matches on a dn containing www_tcet_erikin_com\n"
                    print "OR:   (|(cn=www)(ou:dn:=www_tcet_erikin_com))"
                    print "\t Searches for a cn=www (group) OR a dn containing www_tcet_erikin_com\n"
                    print "NOT:  (!(ou:dn:=www_tcet_erikin_com))"
                    print "\t Searches for a dn NOT containing www_tcet_erikin_com\n"
                    print "--------------------\n"
                elif filter == 'b':
                    # filter is set for browsing the tree
                    break
                elif filter == 'q':
                    break
                else:
                    help = ''               
                break
        else:
            filter = ldapsearch

        return filter

    def Connect(self, config):
        """ Connect to an ldap server """

        # if we are using ssl set location of cacertfile
        if config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["ldapUseSsl"] == '1' and config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["ldapCaCert"] != '':
            ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["ldapCaCert"])

        # set the ldap connection string
        ldapConnString = config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["ldapProtocol"] + "://" + config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["ldapHostname"] + ":" + config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["ldapPort"]

        # initialize the ldap connection
        ldapConn = ldap.initialize(ldapConnString)

        # if config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["ldapUseSsl"] == '1' and config['Ldap']["ldapPort"] == '389'
        # initialize TLS or SSL
        if config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["ldapUseSsl"] == '1' and config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["ldapPort"] == '389':
            ldapConn.start_tls_s()

        # bind to LDAP server
        ldapConn.simple_bind(config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["ldapUser"], config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["ldapUserPassword"])
        
        return ldapConn

    def Disconnect(self, ldapConn):
        """ unbind the connection """
        ldapConn.unbind()



    def LdapCreateFilter(self, filter):
        """ This function takes the filter from the search prompt and generates a 'real'
        LDAP search filter.

        The filter can be:
        www and www.tcet.erikin.com
        www or www.tcet.erikin.com
        not www.tcet.erikin.com

        Boolean searches:
        AND:  (&(cn=www)(ou:dn:=www_tcet_erikin_com))
                  Searches for a cn=www (group) AND matches on a dn containing www_tcet_erikin_com
        OR:   (|(cn=www)(ou:dn:=www_tcet_erikin_com))
                  Searches for a cn=www (group) OR a dn containing www_tcet_erikin_com
        NOT:  (!(ou:dn:=www_tcet_erikin_com))
                  Searches for a dn NOT containing www_tcet_erikin_com
        """
        pass
    
    def LdapExportToLdif(self, dn):
        """ This function will export the chosen dn to stdout or a file.  This allows us to manipulate
        LDAP objects outside of the script """
        pass

    def LdapImportFromLdif(self, ldifFile):
        """ Takes LDIF input from stdin or a file, and adds them to the LDAP tree """
        pass
    
    def PrintToLdif(self, config, dn, attrs):
        """ Prints the LDIF from the attrs array that we have created with Python """
        # find if the user wants to Print to screen, print to file, or both
        outputOrFile = raw_input("Print to [s]creen, print to [f]ile, or [b]oth? [s] ")
        
        if outputOrFile == "":
            outputOrFile = "s"

        if outputOrFile == "b":
            # print to both stdout and ldif file
            self.PrintLdifToStdout(config, dn, attrs)
            self.PrintToLdifFile(config, dn, attrs)
        elif outputOrFile == "f":
            # print the ldif to a file in the config['General']["tempPath"] directory
            self.PrintToLdifFile(config, dn, attrs)
        else:
            # print the ldif to STDOUT
            self.PrintLdifToStdout(config, dn, attrs)

            
    def PrintToLdifFile(self, config, dn, attrs):
        """ print the LDIF to file """
        # generate a unique filename
        utilityObject = Utility.UtilityFunc()
        file = utilityObject.GenerateRandomFilename(config)

        return randomFilename
        # open output file /tmp/randomfilename.ldif
        f = open(config['General']["tempPath"] + '/' + file + '.ldif', 'w')
        try:
            print "Copy and Paste the LDIF below into a text file, or phpLDAPadmin"
            print "---------------------------------------------------------------"
            print
            print "dn: " + dn
            for key, value in attrs:
                print key + ": " + value
            print
        finally:
            f.close()
        print "\nYou may access your LDIF file at " + config['General']["tempPath"] + "/" + file + ".ldif\n"


    def PrintLdifToStdout(self, config, dn, attrs):
        """ print the LDIF to STDOUT """
        print "Copy and Paste the LDIF below into a text file, or phpLDAPadmin"
        print "---------------------------------------------------------------"
        print
        print "dn: " + dn
        for key, value in attrs:
            print key + ": " + value
        print

    def LdapCreateUser(self, config, utilityObject):
        """ Prompts for username and password of a non-ERIKIN user and creates them in the config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]['peopleContainer']

        Here is an example LDIF:
        dn: uid=iawmweb,ou=people,ou=centweb,ou=applications,o=erikin
        cn: iawmweb user
        givenName: iawmweb
        sn: user
        userPassword: team32
        objectClass: inetOrgPerson
        objectClass: erikinPerson
        objectClass: organizationalPerson
        objectClass: Person
        objectClass: ndsLoginProperties
        objectClass: Top
        objectClass: arsProperties
        uid: iawmweb
        ACL: 2#subtree#uid=iawmweb,ou=people,ou=CentWeb,ou=Applications,o=erikin#[All Attributes Rights]
        ACL: 6#entry#uid=iawmweb,ou=people,ou=CentWeb,ou=Applications,o=erikin#loginScript
        ACL: 2#entry#[Public]#messageServer
        ACL: 2#entry#[Root]#groupMembership
        ACL: 6#entry#uid=iawmweb,ou=people,ou=CentWeb,ou=Applications,o=erikin#printJobConfiguration
        ACL: 2#entry#[Root]#networkAddress
        """
        ## DEBUGGING
        if config['General']["debugLevel"] == '5':
            import pdb; pdb.set_trace()

        objectName = "Username? (q => finish) [q] "
        # grab single/multiple groupNames
        userList = utilityObject.GetObjectId(config, objectName)

        failedUserArray =[]
        # loop through userList to generate passwords and add them to webs
        for user in userList:
            print "\nFirst, we will need some information about " + user + "...\n"

            
            newUserGivenName = raw_input("First Name? ")
            newUserSn = raw_input("Last Name? ")
            newUserUid = user
            #generate a random password
            newUserUserPassword = self.generatePasswd(config, utilityObject)
            newUserDn = "uid=" + newUserUid + "," + config['Ldap']['Server' + config['Session']['Ldap']['CurrentServer']]["newUserContainerBaseDn"]

            newLdapUserAttrs = self.NewLdapUserAttrs(config, utilityObject, newUserDn, newUserGivenName, newUserSn, newUserUid, newUserUserPassword)
            create = self.LdapCreateObject(config, newUserDn, newLdapUserAttrs)
        


    def NewLdapUserAttrs(self, config, utilityObject, newUserDn, newUserGivenName, newUserSn, newUserUid, newUserUserPassword):
        """ create the attribute array for the new LDAP user """
        newUserCn = newUserGivenName + " " + newUserSn
        # Example - this code will create an object of the type posixAccount.
        aclValue = "2#subtree#" + newUserDn + "#[All Attributes Rights]"
        aclValue2 = "6#entry#" + newUserDn + "#loginScript"
        aclValue3 = "2#entry#[Public]#messageServer"
        aclValue4 = "2#entry#[Root]#groupMembership"
        aclValue5 = "6#entry#" + newUserDn + "#printJobConfiguration"
        aclValue6 = "2#entry#[Root]#networkAddress"

        attrs = []
        #attrs.append( ("dn", newUserDn) )
        attrs.append( ("uid", newUserUid) )
        attrs.append( ("cn", newUserCn) )
        attrs.append( ("givenName", newUserGivenName) )
        attrs.append( ("sn", newUserSn) )
        attrs.append( ("userPassword", newUserUserPassword) )
        attrs.append( ("objectClass","inetOrgPerson") )
        attrs.append( ("objectClass","erikinPerson") )
        attrs.append( ("objectClass","organizationalPerson") )
        attrs.append( ("objectClass","Person") )
        attrs.append( ("objectClass","ndsLoginProperties") )
        attrs.append( ("objectClass","Top") )
        attrs.append( ("objectClass","arsProperties") )
        attrs.append( ("ACL",aclValue) )
        attrs.append( ("ACL",aclValue2) )
        attrs.append( ("ACL",aclValue3) )
        attrs.append( ("ACL",aclValue4) )
        attrs.append( ("ACL",aclValue5) )
        attrs.append( ("ACL",aclValue6) )
                

        if config['General']["debugLevel"] == '5':
            print attrs

        self.PrintToLdif(config, newUserDn, attrs)

        return attrs

    def generatePasswd(self, config, utilityObject):
        """create password for user
           autogenerate or manual input"""
        autogeneratepw = raw_input("Autogenerate Password for User? (y/n) [y] ")
        if autogeneratepw == "":
            autogeneratepw = 'y'
            
        if autogeneratepw == 'y':
            password = utilityObject.GeneratePassword(config)
        else:
            password = raw_input("User's Password? ")

        return password

